//
//  objc_class_and_object.m
//  objc_test
//
//  Created by wangrui on 13-8-7.
//  Copyright (c) 2013年 PPS. All rights reserved.
//
//  关于objective-c类和对象的理解，并且如何动态添加一个类

#import <objc/objc.h>
#import <objc/runtime.h>

/*
 *该函数能很好的帮助理解objc类的关系. 官方的函数为objc_allocateClassPair
 */
BOOL creat_class_definition (const char *name, const char *superclass_name){
#if !__OBJC2__
    Class meta_class;
    Class super_class;
    Class root_class = nil;
    Class new_class;
    
    // 确保父类存在
    super_class = (Class)objc_lookUpClass (superclass_name);
    if (super_class == nil)
    {
        return NO;
    }
    
    // 确保要创建的类不存在
    if (objc_lookUpClass (name) != nil) {
        return NO;
    }
    
    
    // 查找 root class,因为 meta class 的 isa 指向 root class 的 meta class
    root_class = super_class;
    while( root_class->super_class != nil ) {
        root_class = root_class->super_class;
    }
    ￼
    // 为 class 及其 meta class 分配内存
    new_class = calloc( 2, sizeof(struct objc_class) );
    meta_class = &new_class[1];
    
    // 设置 class
    new_class->isa = meta_class;
    new_class->info = CLS_CLASS;
    meta_class->info = CLS_META;
    
    // 拷贝类名字,这里为了高效率,让 class 与 meta class 都指向同一个类名字符串 new_class->name = malloc (strlen (name) + 1);
    strcpy ((char*)new_class->name, name);
    meta_class->name = new_class->name;
    
    // 分配并置空 method lists,我们可以在之后使用 class_addMethods 向类中增加方法
    new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *) );
    meta_class->methodLists = calloc( 1, sizeof(struct objc_method_list *) );
    
    // 将类加入到继承体系中去:
    // 1,设置类的 super class
    // 2,设置 meta class 的 super class
    // 3,设置 meta class 的 isa
    new_class->super_class = super_class;
    meta_class->super_class = super_class->isa;
    meta_class->isa = (void *)root_class->isa; // 最后,将 class 注册到运行时系统中
    objc_addClass(new_class);
#endif
    
    return YES;
}


void ReportFunction(id self, SEL _cmd) {
    NSLog(@" >> This object is %p.", self);
    NSLog(@" >> Class is %@, and super is %@.", [self class], [self superclass]);
    
    Class prevClass = NULL;
    int count = 1;
    for (Class currentClass = [self class]; currentClass; ++count) {
        prevClass = currentClass;
        NSLog(@" >> Following the isa pointer %d times gives %p", count, currentClass);
        currentClass = object_getClass(currentClass);
        
        if (prevClass == currentClass)
            break;
    }
    
    NSLog(@" >> NSObject's class is %p", [NSObject class]);
    NSLog(@" >> NSObject's meta class is %p", object_getClass([NSObject class]));
}


int main(int argc, const char * argv[])
{
    Class newClass = objc_allocateClassPair([NSString class], "NSStringSubclass", 0);
    class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
    objc_registerClassPair(newClass);
    
    id instanceOfNewClass = [[newClass alloc] init];
    [instanceOfNewClass performSelector:@selector(report)];
    [instanceOfNewClass release];
    
    return 0;
}

